package net.luohuasheng.bee.proxy.mybatis.executor.intercetor;


import net.luohuasheng.bee.proxy.mybatis.common.exception.MybatisException;
import net.luohuasheng.bee.proxy.mybatis.common.utils.CrudUtils;
import net.luohuasheng.bee.proxy.mybatis.executor.processor.BaseProcessor;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.Properties;

import static net.luohuasheng.bee.proxy.mybatis.ConfigurationProxy.END_FLAG;
import static net.luohuasheng.bee.proxy.mybatis.executor.intercetor.BaseInterceptor.Index.MAPPED_STATEMENT_INDEX;
import static net.luohuasheng.bee.proxy.mybatis.executor.intercetor.BaseInterceptor.Index.PARAMETER_INDEX;


/**
 * @author luohuasheng
 */
@Intercepts({
        @Signature(
                type = Executor.class,
                method = "update",
                args = {MappedStatement.class, Object.class}),
        @Signature(
                type = Executor.class,
                method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(
        type = Executor.class,
        method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
public class CrudInterceptor implements BaseInterceptor {


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[MAPPED_STATEMENT_INDEX.getAnInt()];
        if (ms.getResource().endsWith(END_FLAG)) {
            Object parameter = args[PARAMETER_INDEX.getAnInt()];
            BoundSql boundSql = ms.getBoundSql(parameter);
            BaseProcessor processor = CrudUtils.getBaseProcessor(ms.getConfiguration(), ms.getId());
            if (processor != null) {
                boolean isOk = !processor.getJpaTableDto().isTable() && (ms.getSqlCommandType().equals(SqlCommandType.DELETE) || ms.getSqlCommandType().equals(SqlCommandType.INSERT) || ms.getSqlCommandType().equals(SqlCommandType.UPDATE));
                if (isOk) {
                    throw new MybatisException("The method [" + ms.getId() + "] is not allowed to be called!");
                }
                callLog(ms);
                processor.rewrite(invocation, ms, boundSql, parameter);
            }
        }
        BaseProcessor.remoteUpdateExpressionFields();
        return invocation.proceed();
    }


    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 合并属性
    }


}
